#include "OpenGL.h"


namespace GxRendering
{
	PFNWGLSWAPINTERVALEXTPROC OpenGL::wglSwapIntervalEXT;
	PFNGLENABLEIPROC OpenGL::Enablei;
	PFNGLDISABLEIPROC OpenGL::Disablei;
	PFNGLDRAWBUFFERSPROC OpenGL::DrawBuffers;
	PFNGLCLAMPCOLORARBPROC OpenGL::ClampColor;
	PFNGLGENERATEMIPMAPEXTPROC OpenGL::GenerateMipmap;
	PFNGLGETCOMPRESSEDTEXIMAGEPROC OpenGL::GetCompressedTexImage;
	PFNGLCOMPRESSEDTEXIMAGE2DPROC OpenGL::CompressedTexImage2D;
	void BeginUIDrawing()
	{
		int viewport[4];
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		glGetIntegerv(GL_VIEWPORT,viewport);
		glMatrixMode(GL_PROJECTION);
			glPushMatrix();
			glLoadIdentity();
			glOrtho(0,viewport[2],viewport[3],0,1,-1);
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();
		glLoadIdentity();
		glDisable(GL_DEPTH_TEST);
	}

	void EndUIDrawing()
	{
		glPopMatrix();
		glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
		glEnable(GL_DEPTH_TEST);
	}

	RenderBuffer::RenderBuffer(int internalFormat, int w, int h)
	{
		FBO::GenRenderbuffers(1, &rb);
		FBO::BindRenderbuffer(GL_RENDERBUFFER, rb);
		FBO::RenderbufferStorage(GL_RENDERBUFFER, internalFormat, w, h);
		FBO::BindRenderbuffer(GL_RENDERBUFFER, 0);
		itnFmt = internalFormat;
	}

	RenderBuffer::~RenderBuffer()
	{
		FBO::DeleteRenderbuffers(1, &rb);
	}

	unsigned int RenderBuffer::GetHandle()
	{
		return rb;
	}

	void RenderBuffer::SetStorage(int w, int h)
	{
		FBO::BindRenderbuffer(GL_RENDERBUFFER, rb);
		FBO::RenderbufferStorage(GL_RENDERBUFFER, itnFmt, w, h);
		FBO::BindRenderbuffer(GL_RENDERBUFFER, 0);
	}

	FrameBufferObject::FrameBufferObject()
	{
		FBO::GenFramebuffers(1, &fbo);
	}

	FrameBufferObject::~FrameBufferObject()
	{
		FBO::DeleteFramebuffers(1, &fbo);
	}

	void FrameBufferObject::AttachTexture(unsigned int attachment, Texture *tex, unsigned int texTarget, int level)
	{
		AttachTexture(attachment, tex->TexID, texTarget, level);
	}

	void FrameBufferObject::AttachRenderBuffer(unsigned int attachment, GxRendering::RenderBuffer *rb)
	{
		Bind();
		if (rb)
			FBO::FramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, rb->GetHandle());
		else
			FBO::FramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, 0);
		UnBind();
	}

	void FrameBufferObject::Bind()
	{
		glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (int *)&lstFBO);
		FBO::BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
	}

	void FrameBufferObject::UnBind()
	{
		FBO::BindFramebuffer(GL_DRAW_FRAMEBUFFER, lstFBO);
	}

	bool FrameBufferObject::IsReady()
	{
		Bind();
		bool rs = false;
		int state = FBO::CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
		if (state == GL_FRAMEBUFFER_COMPLETE)
			rs = true;
		UnBind();
		return rs;
	}

	void FrameBufferObject::AttachTexture(unsigned int attachment, GLuint texID, unsigned int texTarget, int level)
	{
		Bind();
		FBO::FramebufferTexture2D(GL_FRAMEBUFFER, attachment, texTarget, texID, level);
		UnBind();
	}

	bool OpenGL::Init()
	{
		VBO::LoadProcs();
		FBO::LoadProcs();
		Shader::LoadProcs();
		MultiTexture::LoadProcs();
		wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
		Enablei = (PFNGLENABLEIPROC)wglGetProcAddress("glEnablei");
		Disablei = (PFNGLDISABLEIPROC)wglGetProcAddress("glDisablei");
		DrawBuffers = (PFNGLDRAWBUFFERSPROC)wglGetProcAddress("glDrawBuffers");
		ClampColor = (PFNGLCLAMPCOLORARBPROC)wglGetProcAddress("glClampColorARB");
		GenerateMipmap = (PFNGLGENERATEMIPMAPEXTPROC)wglGetProcAddress("glGenerateMipmapEXT");
		GetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)wglGetProcAddress("glGetCompressedTexImage");
		CompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)wglGetProcAddress("glCompressedTexImage2D");
		return VBO::CanUse && FBO::CanUse&&Shader::CanUse && MultiTexture::CanUse &&
			(wglSwapIntervalEXT != 0) && (Enablei != 0) && (DrawBuffers != 0) && (ClampColor != 0) &&
			(GenerateMipmap != 0) && (GetCompressedTexImage!=0) && (CompressedTexImage2D!=0);
	}

	void OpenGL::SetSwapInterval(int inter)
	{
		wglSwapIntervalEXT(inter);
	}

	OpenGL::GLVersion OpenGL::GetVersion()
	{
		int major=0, minor=0;
		char * version = (char *)glGetString(GL_VERSION);
		major = version[0]-'0';
		minor = version[2]-'0';
		switch (major)
		{
		case 1:
			switch(minor)
			{
			case 0:
				return OpenGL::gv100;
			case 1:
				return OpenGL::gv110;
			case 2:
				return OpenGL::gv120;
			case 3:
				return OpenGL::gv130;
			case 4:
				return OpenGL::gv140;
			case 5:
				return OpenGL::gv150;
			}
			break;
		case 2:
			switch(minor)
			{
			case 0:
				return OpenGL::gv200;
			case 1:
				return OpenGL::gv210;
			}
			break;
		case 3:
			switch (minor)
			{
			case 0:
				return OpenGL::gv300;
			case 1:
				return OpenGL::gv310;
			}
			break;
		}
		if (major >= 3)
			return OpenGL::gvNewer;
		else
			return OpenGL::gvOlder;
	}

	String OpenGL::GetRenderer()
	{
		char * renderer = (char *)glGetString(GL_RENDERER);
		return renderer;
	}
	
}